#include "CSBakeLightVolumes.fxh"

struct PointLight
{
	float4 PosWAndRadius;
	float4 ColorAndIntens;
};

#define MAX_POINT_LIGHTS 128
PointLight gLights[MAX_POINT_LIGHTS];
int gNumLights;

float3 getPointLightStrengthDir(int index, float3 samplePos)
{
	const float3 lightPos = gLights[index].PosWAndRadius.xyz;
	const float lightRadius = gLights[index].PosWAndRadius.w;
	const float lightIntensity = gLights[index].ColorAndIntens.a;

	float3 lightDir = lightPos - samplePos;
	float dist = length(lightDir);
	lightDir = normalize(lightDir);

	float atten = saturate((lightRadius - dist) / lightRadius);
	return lightDir * atten * lightIntensity;
}

[numthreads(8, 8, 8)]
void CS(	uint3 GroupID : SV_GroupID,
			uint3 DispatchThreadID : SV_DispatchThreadID,
			uint3 GroupThreadID : SV_GroupThreadID,
			uint GroupIndex : SV_GroupIndex )
{
	float3 lightVolPos = gLightVolPosTex.Load(int2(GroupID.x, 0)).xyz;
	float3 lightVolScale = gLightVolScaleTex.Load(int2(GroupID.x, 0)).xyz;

	int threadOffsetX = gLightVolSectionThreadOffsetXTex.Load(int2(GroupID.x, 0)).x;
	float3 threadPosInSection = float3(DispatchThreadID - int3(threadOffsetX, 0, 0)) + float3(0.5f, 0.5f, 0.5f);

	float3 samplePos = lightVolPos + threadPosInSection * lightVolScale;

#ifdef AXES_4
	float3 axis0Val, axis1Val, axis2Val, axis3Val;
	read4Axes(DispatchThreadID, axis0Val, axis1Val, axis2Val, axis3Val);
	
	for(int i = 0; i < gNumLights; i++)
	{
		const float3 axis0 = float3(0, 1, 0);
		const float3 axis1 = float3(0, -0.341987, 0.939705);
		const float3 axis2 = float3( 0.813808, -0.341987, -0.469852);
		const float3 axis3 = float3(-0.813808, -0.341987, -0.469852);

		float3 lightColor = gLights[i].ColorAndIntens.rgb;
		float3 lightStrengthDir = getPointLightStrengthDir(i, samplePos);

		axis0Val += lightColor * max(lightStrengthDir.y, 0); // unnecessary to do dot, since axis0 is standard axis
		axis1Val += lightColor * max(dot(lightStrengthDir, axis1), 0);
		axis2Val += lightColor * max(dot(lightStrengthDir, axis2), 0);
		axis3Val += lightColor * max(dot(lightStrengthDir, axis3), 0);
	}

	write4Axes(DispatchThreadID, axis0Val, axis1Val, axis2Val, axis3Val);

#else
	float3 xPos, xNeg, yPos, yNeg, zPos, zNeg;
	read6Axes(DispatchThreadID, xPos, xNeg, yPos, yNeg, zPos, zNeg);

	for(int i = 0; i < gNumLights; i++)
	{
		float3 lightColor = gLights[i].ColorAndIntens.rgb;
		float3 lightStrengthDir = getPointLightStrengthDir(i, samplePos);

		xPos += lightColor * max( lightStrengthDir.x, 0);
		xNeg += lightColor * max(-lightStrengthDir.x, 0);
		yPos += lightColor * max( lightStrengthDir.y, 0);
		yNeg += lightColor * max(-lightStrengthDir.y, 0);
		zPos += lightColor * max( lightStrengthDir.z, 0);
		zNeg += lightColor * max(-lightStrengthDir.z, 0);
	}

	write6Axes(DispatchThreadID, xPos, xNeg, yPos, yNeg, zPos, zNeg);
#endif
}

technique11 tech
{
	pass P0
	{
		SetComputeShader(CompileShader(cs_5_0, CS())); 
	}
}
